package com.ttg.common.utils.sm;



import com.ttg.common.utils.Base64Util;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class SM4Utils {


    /**
     * 密钥是否是hex串
     */
    private static boolean hexKey = true;

    /**
     * 是否补长
     */
    private static boolean padding = true;

    /**
     * 加密结果是否转换 base64
     * 默认 hex串
     */
    private static boolean outputBase64 = false;

    /**
     * 解密结果是否转换hax 串
     * 默认 字符串
     */
    private static boolean outHexFormat = false;

    /**
     * 待解密文 是否 base64 串
     */
    private static boolean inputBase64 = false;


    public static String encryptDataECB(String plainText, String secretKey) {
        return encryptDataECB(plainText, secretKey, hexKey, padding, outputBase64);
    }

    public static String encryptDataECB(String plainText, String secretKey, boolean hexString, boolean padding, boolean outputBase64) {
        try {

            byte[] keyBytes;
            if (hexString) {
                keyBytes = Util.hexStringToBytes(secretKey);
            } else {
                keyBytes = secretKey.getBytes();
            }
            byte[] encrypted = encryptDataECB(plainText.getBytes(), keyBytes, padding);

            String cipherText = null;
            if (outputBase64) {
                cipherText = Base64Util.encodeData(encrypted);
            } else {
                cipherText = CryptoUtil.bin2hex(encrypted);
            }

            return cipherText;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static byte[] encryptDataECB(byte[] plainBytes, byte[] keyBytes, boolean padding) {
        try {
            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = padding;
            ctx.mode = SM4.SM4_ENCRYPT;
            SM4 sm4 = new SM4();
            sm4.sm4SetkeyEnc(ctx, keyBytes);
            byte[] encrypted = sm4.sm4CryptEcb(ctx, plainBytes);
            return encrypted;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String decryptDataECB(String cipherText, String secretKey) {
        return decryptDataECB(cipherText, secretKey, padding, inputBase64, outHexFormat);
    }

    public static String decryptDataECB(String cipherText, String secretKey, boolean padding, boolean inputBase64, boolean outHexFormat) {
        try {
            byte[] decryptData = null;
            if (inputBase64) {
                decryptData = Base64Util.decodeData(cipherText);
            } else {
                decryptData = CryptoUtil.hex2bin(cipherText);
            }
            byte[] keyBytes;
            if (hexKey) {
                keyBytes = Util.hexStringToBytes(secretKey);
            } else {
                keyBytes = secretKey.getBytes();
            }
            byte[] decrypted = decryptDataECB(decryptData, keyBytes, padding);
            String returnData = null;
            if (outHexFormat) {
                returnData = CryptoUtil.bin2hex(decrypted);
            } else {
                returnData = new String(decrypted, StandardCharsets.UTF_8);
            }
            return returnData;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static byte[] decryptDataECB(byte[] decryptData, byte[] keyBytes, boolean padding) {
        try {
            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = padding;
            ctx.mode = SM4.SM4_DECRYPT;
            SM4 sm4 = new SM4();
            sm4.sm4SetkeyDec(ctx, keyBytes);
            return sm4.sm4CryptEcb(ctx, decryptData);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    public static String encryptDataCBC(String plainText, String secretKey, String iv) {
        return encryptDataCBC(plainText, secretKey, iv, hexKey, padding, outputBase64);
    }

    public static String encryptDataCBC(String plainText, String secretKey, String iv, boolean hexString, boolean padding, boolean outputBase64) {
        try {
            byte[] keyBytes;
            byte[] ivBytes;
            if (hexString) {
                keyBytes = Util.hexStringToBytes(secretKey);
                ivBytes = Util.hexStringToBytes(iv);
            } else {
                keyBytes = secretKey.getBytes();
                ivBytes = iv.getBytes();
            }
            byte[] encrypted = encryptDataCBC(plainText.getBytes(StandardCharsets.UTF_8), keyBytes, ivBytes, padding);
            String cipherText = null;
            if (outputBase64) {
                cipherText = Base64Util.encodeData(encrypted);
            } else {
                cipherText = CryptoUtil.bin2hex(encrypted);
            }
            if (cipherText.trim().length() > 0) {
                Pattern p = Pattern.compile("\\s*|\t|\r|\n");
                Matcher m = p.matcher(cipherText);
                cipherText = m.replaceAll("");
            }
            return cipherText;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static byte[] encryptDataCBC(byte[] plainBytes, byte[] keyBytes, byte[] ivBytes, boolean padding) {

        try {
            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = padding;
            ctx.mode = SM4.SM4_ENCRYPT;
            SM4 sm4 = new SM4();
            sm4.sm4SetkeyEnc(ctx, keyBytes);
            return sm4.sm4CryptCbc(ctx, ivBytes, plainBytes);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    public static String decryptDataCBC(String cipherText, String secretKey, String iv) {
        return decryptDataCBC(cipherText, secretKey, iv, hexKey, padding, inputBase64, outHexFormat);
    }


    public static String decryptDataCBC(String cipherText, String secretKey, String iv, boolean hexKey, boolean padding, boolean inputBase64, boolean outHexFormat) {
        try {

            byte[] keyBytes;
            byte[] ivBytes;
            if (hexKey) {
                keyBytes = Util.hexStringToBytes(secretKey);
                ivBytes = Util.hexStringToBytes(iv);
            } else {
                keyBytes = secretKey.getBytes();
                ivBytes = iv.getBytes();
            }
            byte[] decryptData = null;
            if (inputBase64) {
                decryptData = Base64Util.decodeData(cipherText);
            } else {
                decryptData = CryptoUtil.hex2bin(cipherText);
            }
            byte[] decrypted = decryptDataCBC(decryptData, keyBytes, ivBytes, padding);
            String returnData = null;
            if (outHexFormat) {
                returnData = CryptoUtil.bin2hex(decrypted);
            } else {
                returnData = new String(decrypted, StandardCharsets.UTF_8);
            }

            return returnData;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static byte[] decryptDataCBC(byte[] decryptData, byte[] keyBytes, byte[] ivBytes, boolean padding) {
        try {
            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = padding;
            ctx.mode = SM4.SM4_DECRYPT;
            SM4 sm4 = new SM4();
            sm4.sm4SetkeyDec(ctx, keyBytes);
            return sm4.sm4CryptCbc(ctx, ivBytes, decryptData);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

}

